﻿using Grpc.Core.Interceptors;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Security.Claims;
using System.Security;
using System.Text;
using System.Threading.Tasks;
using Zy.Shared.Consts;
using Zy.Shared.Enums;
using Zy.Shared.Constraint.Dtos;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using Zy.Shared.Cache.Services;
using Zy.Shared.Extensions;

namespace Zy.Shared.Rpc.Interceptors
{
    public class GrpcAuthInterceptor(ZyUserContext userContext,
        ICacheService cacheService,
        IConfiguration configuration) : Interceptor
    {
        public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
        TRequest request,
        ServerCallContext context,
        UnaryServerMethod<TRequest, TResponse> continuation)
        {
            if (!context.Method.StartsWith("Public"))
            {
                // 检查 Authorization 头部
                var authHeader = context?.RequestHeaders?.GetValue("Authorization");
                if (authHeader == null)
                {
                    throw new RpcException(new Status(StatusCode.Unauthenticated, "Missing authorization header"));
                }

                // 解析令牌，验证其有效性
                var token = authHeader.Split(' ')[1];
                if (!await IsValidToken(token))
                {
                    throw new RpcException(new Status(StatusCode.Unauthenticated, "Invalid token"));
                }
            }
            return await continuation(request, context);
        }

        private async Task<bool> IsValidToken(string token)
        {
            // 在这里实现你的令牌验证逻辑
            // 返回 true 如果令牌有效，否则返回 false
            var claimsPrincipal = ParseToken(token, configuration["JwtConfig:SecretKey"]);
            userContext.Id = long.Parse(claimsPrincipal?.Claims?.FirstOrDefault(x => x.Type == "Id")?.Value);
            userContext.Account = claimsPrincipal?.Claims?.FirstOrDefault(x => x.Type == "Account")?.Value;
            userContext.Name = claimsPrincipal.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Name)?.Value;
            userContext.RoleIds = claimsPrincipal.Claims.Where(x => x.Type == ClaimTypes.Role).Select(x => long.Parse(x.Value)).ToList();
            userContext.ClientType = (ClientTypeEnum)int.Parse(claimsPrincipal.Claims.FirstOrDefault(x => x.Type == "ClientType")?.Value);
            userContext.Email = claimsPrincipal.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Email)?.Value;
            userContext.Token= token;
            var cacheKey = CacheKeyConsts.userLoginObjCacheKeyPrefix + ":" + userContext.ClientType.GetDescription() + ":" + claimsPrincipal.Claims.FirstOrDefault(x => x.Type == "Id")?.Value;
            var userInfo = await cacheService.GetAsync<UserInfoCacheAble>(cacheKey);
            if (userInfo == null)
            {
               return false;
            }
            else
            {
                userContext.DataScope = userInfo.DataScope;
            }
            return true;
        }
        /// <summary>
        /// 解析JWT
        /// </summary>
        /// <param name="jwt"></param>
        /// <param name="secretKey"></param>
        /// <returns></returns>
        /// <exception cref="SecurityTokenException"></exception>
        private static ClaimsPrincipal ParseToken(string jwt, string secretKey)
        {
            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey)),
                ValidateIssuer = false, // 不验证发行者
                ValidateAudience = false, // 不验证受众
                RequireExpirationTime = true, // 需要过期时间
                ValidateLifetime = true // 验证令牌是否过期
            };

            var handler = new JwtSecurityTokenHandler();
            SecurityToken securityToken;
            var principal = handler.ValidateToken(jwt, tokenValidationParameters, out securityToken);
            var jwtSecurityToken = securityToken as JwtSecurityToken;
            if (jwtSecurityToken == null || !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase))
                throw new SecurityTokenException("无效的Token");

            return principal;
        }
    }
}
